#include "vsf.h"

#define VSFAV_EVT_FRAME				VSFSM_EVT_USER

static struct vsfsm_state_t *
vsfav_sync_evthandler(struct vsfsm_t *sm, vsfsm_evt_t evt)
{
	struct vsfav_sync_t *sync = (struct vsfav_sync_t *)sm->user_data;
	struct vsfav_stream_sync_t *stream;

	switch (evt)
	{
	case VSFSM_EVT_INIT:
	again:
		if (sync->interval)
		{
			vsftimer_create(sm, sync->interval, 1, VSFSM_EVT_TIMER);
			break;
		}
	case VSFSM_EVT_TIMER:
		while (sync->pending != sync->streamlist.next)
		{
			if (!sync->pending)
				sync->pending = sync->streamlist.next;
			stream = vsflist_get_container(sync->pending,
					struct vsfav_stream_sync_t, list);
			if (vsfsm_sem_pend(&stream->instream->frame_sync, sm))
				return NULL;
	case VSFAV_EVT_FRAME:
			sync->pending = sync->pending->next;
			if (!sync->pending)
			{
				sync->pending = sync->streamlist.next;
				while (sync->pending != NULL)
				{
					stream = vsflist_get_container(sync->pending,
							struct vsfav_stream_sync_t, list);
					vsfsm_sem_post(&stream->outstream.frame_sync);
				}
				goto again;
			}
		}
		break;
	}
	return NULL;
}

vsf_err_t vsfav_sync_init(struct vsfav_sync_t *sync, uint32_t interval)
{
	if (!interval) return VSFERR_INVALID_PARAMETER;
	memset(sync, 0, sizeof(*sync));
	sync->interval = interval;
	sync->sm.init_state.evt_handler = vsfav_sync_evthandler;
	sync->sm.user_data = sync;
	return VSFERR_NONE;
}

vsf_err_t vsfav_sync_add(struct vsfav_sync_t *sync,
		struct vsfav_stream_sync_t *stream)
{
	if (!stream->instream) return VSFERR_INVALID_PARAMETER;
	stream->outstream.stream = stream->instream->stream;
	vsfsm_sem_init(&stream->instream->frame_sync, 0, VSFAV_EVT_FRAME);

	vsflist_add_head(&sync->streamlist, &stream->list);
	return VSFERR_NONE;
}

vsf_err_t vsfav_sync_start(struct vsfav_sync_t *sync)
{
	return sync->streamlist.next == NULL ? VSFERR_FAIL : vsfsm_init(&sync->sm);
}
